// Copyright 2022 The Google Research Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef THIRD_PARTY_DNN_ACCELERATOR_HLS_TEST_COMMON_ACCELERATORTEST_H_
#define THIRD_PARTY_DNN_ACCELERATOR_HLS_TEST_COMMON_ACCELERATORTEST_H_

#include "src/AccelTypes.h"

#include <mc_connections.h>
#include <systemc.h>
#include <mc_scverify.h>
#include "src/ArchitectureParams.h"
#include "src/AcceleratorTop.h"

SC_MODULE(AcceleratorHarness) {
  sc_clock clk;
  sc_signal<bool> rstn;

  Connections::Combinational<Params> paramsIn;
  Connections::Combinational<VectorParams> vectorParamsIn;
  Connections::Combinational<MemoryRequest> inputAddressRequest[NUM_CORES];
  Connections::Combinational<Pack1D<INPUT_DATATYPE, DIMENSION> >
      inputDataResponse[NUM_CORES];
  Connections::Combinational<MemoryRequest> weightAddressRequest[NUM_CORES];
  Connections::Combinational<Pack1D<WEIGHT_DATATYPE, DIMENSION> >
      weightDataResponse[NUM_CORES];
  Connections::Combinational<int> vectorFetchAddressRequest[NUM_CORES];
  Connections::Combinational<Pack1D<OUTPUT_DATATYPE, DIMENSION> >
      vectorFetchDataResponse[NUM_CORES];
  Connections::Combinational<Pack1D<OUTPUT_DATATYPE, DIMENSION> >
      vectorUnitOutput[NUM_CORES];
  Connections::Combinational<int> outputAddress[NUM_CORES];
  Connections::SyncChannel done[NUM_CORES];

  AcceleratorHarness(sc_module_name, Params, VectorParams, INPUT_DATATYPE *);
  SC_HAS_PROCESS(AcceleratorHarness);

 private:
  Params params;
  VectorParams vectorParams;
  INPUT_DATATYPE *mainMemory;
  CCS_DESIGN(AcceleratorTop) CCS_INIT_S1(accelerator);

  void memAccessBurst(
      Connections::Combinational<MemoryRequest> addressRequest[NUM_CORES],
      Connections::Combinational<Pack1D<INPUT_DATATYPE, DIMENSION> >
          dataResponse[NUM_CORES]);
  void memAccessPack(
      Connections::Combinational<int> addressRequest[NUM_CORES],
      Connections::Combinational<Pack1D<INPUT_DATATYPE, DIMENSION> >
          dataResponse[NUM_CORES]);
  void memAccess(
      Connections::Combinational<int> addressRequest[NUM_CORES],
      Connections::Combinational<OUTPUT_DATATYPE> dataResponse[NUM_CORES]);

  void reset();
  void memoryAccessInputs();
  void memoryAccessWeights();
  void memoryAccessVector();
  void storeOutputs();
  void sendParams();
  void sendVectorParams();
  void waitForDone();
};

void run_op(const Params params, const VectorParams vectorParams,
            INPUT_DATATYPE *mainMemory);

#endif  // THIRD_PARTY_DNN_ACCELERATOR_HLS_TEST_COMMON_ACCELERATORTEST_H_
